package com.geline.web.interceptor;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.geline.cloud.core.BaseSessionService;
import com.geline.cloud.util.DynamicSqlUtil;
import com.geline.web.annotation.SqlAction;
import com.geline.web.enums.ActionEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Map;

@Slf4j
public class SqlActionInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Method method = handlerMethod.getMethod();
            SqlAction[] list = method.getAnnotationsByType(SqlAction.class);
            if(list!=null && list.length > 0){
                for(SqlAction sqlAction : list){
                    if(sqlAction.type()== ActionEnum.before){
                        handleBefore(sqlAction, request);
                    }
                }
            }
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Method method = handlerMethod.getMethod();
            SqlAction[] list = method.getAnnotationsByType(SqlAction.class);
            if(list!=null && list.length > 0){
                for(SqlAction sqlAction : list){
                    if(sqlAction.type()== ActionEnum.after){
                        handleAfter(sqlAction, request);
                    }
                }
            }
        }
    }

    private void handleBefore(SqlAction sqlAction, HttpServletRequest request) {
        String sql = sqlAction.writeSql();
        if(StrUtil.isBlank(sql)){
            throw new RuntimeException("@SqlAction writeSql is blank !");
        }
        String runSql = DynamicSqlUtil.parseSQL(sql, createParaMap(request));
        try {
            int number = getJdbcTemplate().update(runSql);
            if(number>0){
                log.info("handleBefore : {}; number = {}", runSql, number);
            }
        }  catch (Exception e) {
            e.printStackTrace();
            if(StrUtil.isNotBlank(sqlAction.errorMsg())){
                throw new RuntimeException(sqlAction.errorMsg());
            }else{
                throw e;
            }
        }
    }

    private void handleAfter(SqlAction sqlAction, HttpServletRequest request) {
        String sql = sqlAction.writeSql();
        if(StrUtil.isBlank(sql)){
            throw new RuntimeException("@SqlAction writeSql is blank !");
        }
        String runSql = DynamicSqlUtil.parseSQL(sql, createParaMap(request));
        try {
            int number = getJdbcTemplate().update(runSql);
            if(number>0){
                log.info("handleAfter : {}; number = {}", runSql, number);
            }
        }  catch (Exception e) {
            e.printStackTrace();
            if(StrUtil.isNotBlank(sqlAction.errorMsg())){
                throw new RuntimeException(sqlAction.errorMsg());
            }else{
                throw e;
            }
        }
    }

    protected JdbcTemplate getJdbcTemplate() {
        return SpringUtil.getBean(JdbcTemplate.class);
    }

    protected BaseSessionService getSessionService() {
        return SpringUtil.getBean(BaseSessionService.class);
    }

    protected Map<String, Object> createParaMap(HttpServletRequest request){
        Map<String, Object> example = (Map<String, Object>) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
        example.put("sessionUserId", getSessionService().getUserId());
        Serializable tenantId = getSessionService().getTenantId();
        if(tenantId!=null){
            example.put("sessionTenantId", tenantId);
        }
        return example;
    }
}
